import os
import yaml
import json
import logging
from typing import Dict, Any, Optional, List
import datetime

logger = logging.getLogger(__name__)

class DSLExecutor:
    """DSL执行器 - 执行DSL流程并生成结果"""
    
    def __init__(self, out_dir: str):
        """初始化DSL执行器
        
        Args:
            out_dir: 输出目录
        """
        self.out_dir = out_dir
        os.makedirs(out_dir, exist_ok=True)
        
    async def run(self, flow_def: Dict, logs: List[Dict], context: Dict) -> Dict:
        """执行DSL流程
        
        Args:
            flow_def: Flow定义（YAML解析后的字典）
            logs: 经过预处理（包含run_stage_id）的日志列表
            context: 执行上下文 (用于传递原始的 log_path 等信息)
            
        Returns:
            Dict: 执行结果，包含trace、evidence、all_run_stage_results等信息
        """
        try:
            flow_context = {
                "flow_id": flow_def.get("id", "unknown"),
                "log_path": context.get("log_file", ""),
                "base_log_path": context.get("base_log_path", ""),
                "variables": {},
                "evidence": [],
                "trace": [],
                "final_state": None,
                "final_state_message": None,
                "artifacts": [],
                "last_match_timestamp": None,
                "current_run_stage_id": -1, # 初始化为-1，表示尚未进入任何阶段
                "all_run_stage_results": [] # 存储所有运行阶段的匹配结果
            }
            
            current_state = flow_def.get("start")
            if not current_state:
                raise ValueError("Flow必须指定start状态")
            
            # 遍历所有日志条目
            for log_entry in logs:
                # 如果是新的运行阶段，重置流程状态
                if log_entry['run_stage_id'] != flow_context['current_run_stage_id']:
                    # 保存上一个阶段的结果（如果存在）
                    if flow_context['current_run_stage_id'] != -1:
                        flow_context['all_run_stage_results'].append({
                            "run_stage_id": flow_context['current_run_stage_id'],
                            "final_state": flow_context["final_state"],
                            "final_state_message": flow_context["final_state_message"],
                            "trace": flow_context["trace"].copy(),
                            "evidence": flow_context["evidence"].copy(),
                        })
                    
                    # 重置当前阶段的状态
                    flow_context['current_run_stage_id'] = log_entry['run_stage_id']
                    current_state = flow_def.get("start") # 重置到起始状态
                    flow_context['last_match_timestamp'] = None # 清空时间戳
                    flow_context['trace'] = [] # 清空trace
                    flow_context['evidence'] = [] # 清空evidence
                    flow_context['final_state'] = None
                    flow_context['final_state_message'] = None
                    logger.info(f"检测到新的运行阶段 (ID: {flow_context['current_run_stage_id']})，重置流程到状态: {current_state}")

                # 执行状态机
                if current_state: # 只有当有活动状态时才进行匹配
                    state_def = flow_def["states"].get(current_state)
                    if not state_def:
                        # 如果在当前阶段内找不到状态定义，说明流程中断，但在新的阶段会重置
                        # 这里我们只是跳过当前日志，等待下一个日志来触发状态机的重置
                        continue
                    
                    action = state_def.get("action")
                    if not action:
                        raise ValueError(f"状态必须指定action: {current_state}")
                    
                    trace_entry = {
                        "state": state_def,
                        "name": current_state,
                        "action": action,
                        "log_entry_time": log_entry.get('datetime') # 记录当前日志时间
                    }
                    
                    if action == "match_log_patterns":
                        result = await self._act_match_log_patterns(state_def, log_entry, flow_context)
                        trace_entry["ok"] = result
                        trace_entry["message"] = state_def.get("message", "")
                        
                        current_state = state_def.get("on_true" if result else "on_false")
                        
                        flow_context["trace"].append(trace_entry)

                        # 立即处理后续的 write_output 状态（无需消耗新的日志）
                        while current_state:
                            next_state_def = flow_def["states"].get(current_state)
                            if not next_state_def:
                                break
                            next_action = next_state_def.get("action")
                            if next_action != "write_output":
                                break

                            message = next_state_def.get("message", "")
                            await self._act_write_output(message, flow_context)

                            write_trace_entry = {
                                "state": next_state_def,
                                "name": current_state,
                                "action": next_action,
                                "log_entry_time": log_entry.get('datetime'),
                                "message": message
                            }
                            flow_context["trace"].append(write_trace_entry)

                            # 进入下一个状态
                            current_state = next_state_def.get("next")
                            if not current_state:
                                flow_context["final_state"] = write_trace_entry["name"]
                                flow_context["final_state_message"] = message

                    elif action == "write_output":
                        message = state_def.get("message", "")
                        await self._act_write_output(message, flow_context)
                        trace_entry["message"] = message
                        
                        current_state = state_def.get("next")
                        
                        if not current_state:
                            flow_context["final_state"] = trace_entry["name"]
                            flow_context["final_state_message"] = message

                        flow_context["trace"].append(trace_entry)
                        
                        # 若还有连续的 write_output，继续处理
                        while current_state:
                            next_state_def = flow_def["states"].get(current_state)
                            if not next_state_def:
                                break
                            next_action = next_state_def.get("action")
                            if next_action != "write_output":
                                break

                            message = next_state_def.get("message", "")
                            await self._act_write_output(message, flow_context)

                            write_trace_entry = {
                                "state": next_state_def,
                                "name": current_state,
                                "action": next_action,
                                "log_entry_time": log_entry.get('datetime'),
                                "message": message
                            }
                            flow_context["trace"].append(write_trace_entry)

                            current_state = next_state_def.get("next")
                            if not current_state:
                                flow_context["final_state"] = write_trace_entry["name"]
                                flow_context["final_state_message"] = message
                    
                    # 对于非 write_output 且已经追加 trace 的分支，此处无需重复 append
            
            # 处理最后一个运行阶段的结果
            if flow_context['current_run_stage_id'] != -1: # 确保至少有一个阶段
                 flow_context['all_run_stage_results'].append({
                    "run_stage_id": flow_context['current_run_stage_id'],
                    "final_state": flow_context["final_state"],
                    "final_state_message": flow_context["final_state_message"],
                    "trace": flow_context["trace"].copy(),
                    "evidence": flow_context["evidence"].copy(),
                })


            report_path = os.path.join(self.out_dir, "explain.json")
            flow_context["artifacts"].append(report_path)
            
            if flow_context["last_match_timestamp"]:
                flow_context["last_match_timestamp"] = flow_context["last_match_timestamp"].isoformat(timespec='microseconds')

            with open(report_path, "w", encoding="utf-8") as f:
                json.dump(flow_context, f, ensure_ascii=False, indent=2)
            
            return flow_context
            
        except Exception as e:
            logger.error(f"Flow执行失败: {e}")
            raise
            
    async def _act_match_log_patterns(self, state_def: Dict, current_log_entry: Dict, context: Dict) -> bool:
        """执行日志匹配动作"""
        try:
            import re
            
            pattern = state_def.get("pattern")
            
            if not pattern:
                logger.error(f"match_log_patterns动作缺少pattern参数: {state_def.get('name')}")
                return False

            if current_log_entry['run_stage_id'] != context['current_run_stage_id']:
                return False

            line = current_log_entry['message']  # 使用 message 而非 full_message

            if pattern.startswith("re:"):
                pattern_to_match = pattern[3:]
            else:
                pattern_to_match = re.escape(pattern)
            
            match = re.search(pattern_to_match, line)
            if match:
                timestamp_pattern = re.compile(r"^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}[.,]\d{1,6})")  # 支持 1-6 位小数
                timestamp_match = timestamp_pattern.match(current_log_entry['full_message'])  # 在 full_message 中匹配时间戳
                
                if timestamp_match:
                    current_timestamp_str = timestamp_match.group(1)
                    current_timestamp = datetime.datetime.strptime(current_timestamp_str.replace(',', '.'), "%Y-%m-%d %H:%M:%S.%f")

                    if context["last_match_timestamp"] and current_timestamp <= context["last_match_timestamp"]:
                        return False # 跳过不符合时间顺序的匹配
                    
                    context["evidence"].append({
                        "pattern": pattern,
                        "matched": match.group(0),
                        "line": line.strip(),
                        "timestamp": current_timestamp_str,
                        "file": current_log_entry.get('source_file', 'unknown'),
                        "run_stage_id": current_log_entry['run_stage_id'] # 记录运行阶段ID
                    })
                    context["last_match_timestamp"] = current_timestamp
                    return True
            
            return False
            
        except Exception as e:
            logger.error(f"日志匹配失败: {e}")
            return False
            
    async def _act_write_output(self, message: str, context: Dict):
        """执行输出写入动作"""
        try:
            # 写入note.json (这个文件通常是最终结果，可以考虑如何整合多阶段信息)
            note = {
                "flow_id": context["flow_id"],
                "message": message,
                "artifacts": context["artifacts"],
                "run_stage_id": context['current_run_stage_id'] # 记录运行阶段ID
            }
            
            note_path = os.path.join(self.out_dir, f"note_stage_{context['current_run_stage_id']}.json")
            context["artifacts"].append(note_path)
            
            with open(note_path, "w", encoding="utf-8") as f:
                json.dump(note, f, ensure_ascii=False, indent=2)
                
        except Exception as e:
            logger.error(f"输出写入失败: {e}")
            raise